package com.base.common.alipay.util;

import com.alibaba.fastjson.JSONObject;
import com.alipay.api.AlipayApiException;
import com.alipay.api.AlipayClient;
import com.alipay.api.DefaultAlipayClient;
import com.alipay.api.domain.AlipayTradeRefundModel;
import com.alipay.api.internal.util.AlipaySignature;
import com.alipay.api.request.AlipayFundTransUniTransferRequest;
import com.alipay.api.request.AlipayTradePagePayRequest;
import com.alipay.api.request.AlipayTradeRefundRequest;
import com.alipay.api.response.AlipayFundTransUniTransferResponse;
import com.alipay.api.response.AlipayTradeRefundResponse;
import com.base.common.alipay.config.AlipayConfig;
import com.base.common.edu.util.Dateutil;

import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;

/**
 * @author ?????
 * @date 2020年6月12日
 * @description <p>支付宝支付工具类</p>
 */
public class AlipayUtil {
	
	/*
	 * 支付页面
	 * subject 商品名称
	 * body 商品介绍，概览信息
	 * timeout_express 该笔订单允许的最晚付款时间，逾期将关闭交易。取值范围：1m～15d。m-分钟，h-小时，d-天，1c-当天（1c-当天的情况下，无论交易何时创建，都在0点关闭）。 该参数数值不接受小数点， 如 1.5h，可转换为 90m
	 * total_amount 交易额，即收款面额
	 * returnUrlPath 页面跳转同步通知页面路径,Get请求，自定义
	 * notifyUrlPath 自定义异步回调，工程相对路径，如接口名，Post请求，自定义
	 * passback_params 自定义回调参数，如订单号。请求的时候放啥返回就是啥
	 * extend_params 公用扩展参数
	 */
	public static String sponserPay(String subject, String body, String total_amount, String timeout_express, String serverip, String returnUrlPath, String notifyUrlPath, String passback_params) throws IOException{
		JSONObject json = new JSONObject();
		String URL = AlipayConfig.URL;
		String APP_ID  = AlipayConfig.APPID;
		String APP_PRIVATE_KEY = AlipayConfig.RSA_PRIVATE_KEY;
		String FORMAT = AlipayConfig.FORMAT;
		String CHARSET = AlipayConfig.CHARSET;
		String ALIPAY_PUBLIC_KEY = AlipayConfig.ALIPAY_PUBLIC_KEY;
		String SIGN_TYPE = AlipayConfig.SIGNTYPE;
		AlipayClient alipayClient =  new  DefaultAlipayClient(URL,APP_ID,APP_PRIVATE_KEY,FORMAT,CHARSET,ALIPAY_PUBLIC_KEY,SIGN_TYPE);
		AlipayTradePagePayRequest alipayRequest =  new  AlipayTradePagePayRequest(); //创建API对应的request
    	
    	//在公共参数中设置回跳和通知地址 
		alipayRequest.setReturnUrl( serverip + returnUrlPath );
	    alipayRequest.setNotifyUrl( serverip + notifyUrlPath ); 
	    /*
	     * 往BizContent放订单相关信息，json串
	     * 官方请求参数文档传送门：https://opendocs.alipay.com/apis/api_1/alipay.trade.page.pay
	     */
	    // 交易号，即时间戳
	    json.put("out_trade_no", Dateutil.getTimeStampString());
	    // 销售产品码，商家和支付宝签约的产品码。
	    json.put("product_code", "FAST_INSTANT_TRADE_PAY");
	    // 商品名称
	    json.put("subject", subject);
	    // 产品价格
	    json.put("total_amount", total_amount);
	    // 公用回传参数，如果请求时传递了该参数，则返回给商户时会回传该参数。可拼接扩展参数
	    json.put("passback_params", passback_params);
	    // 对一笔交易的具体描述信息
	    json.put("body", body);
	    // 订单有效时间，两分钟, 填写2m
	    json.put("timeout_express", timeout_express);
	    alipayRequest.setBizContent(json.toJSONString()); //填充业务参数 
	    String form= "" ;
	    try  {
	        form = alipayClient.pageExecute(alipayRequest).getBody();  //调用SDK生成表单 
	        return form;
	    }  catch  (AlipayApiException e) {
	        e.printStackTrace();
	        return "";
	    }
	}
	
	/**
	 * 验签：支付回调，成功或失败信息
	 * @return
	 * @throws AlipayApiException 
	 * @throws UnsupportedEncodingException 
	 */
	public static Map<String, String> verify(HttpServletRequest request ) throws AlipayApiException, UnsupportedEncodingException{
		// 获取支付宝POST过来反馈信息(官方案例)
        Map<String, String> params = new HashMap<String, String>();
        Map<String, String[]> requestParams = request.getParameterMap();
        for (Iterator<String> iter = requestParams.keySet().iterator(); iter.hasNext();) {
            String name = (String) iter.next();
            String[] values = (String[]) requestParams.get(name);
            String valueStr = "";
            for (int i = 0; i < values.length; i++) {
                valueStr = (i == values.length - 1) ? valueStr + values[i] : valueStr + values[i] + ",";
            }
            // 乱码解决，这段代码在出现乱码时使用
            // valueStr = new String(valueStr.getBytes("ISO-8859-1"), "utf-8");
            params.put(name, valueStr);
        }
        // 调用SDK验证签名
        boolean signVerified = AlipaySignature.rsaCheckV1(params, AlipayConfig.ALIPAY_PUBLIC_KEY, AlipayConfig.CHARSET, AlipayConfig.SIGNTYPE);
        if (signVerified) {// 验证成功
            // 交易状态
            String trade_status = new String(request.getParameter("trade_status").getBytes("ISO-8859-1"), "UTF-8");
            if (trade_status.equals("TRADE_FINISHED")) {
//                System.out.println("交易结束，不可退款");
                return params;
            } else if (trade_status.equals("TRADE_SUCCESS")) {
                return params;
            }
        } else {// 验证失败
        }
		return null;
	}
	
	/**
	 * 退款: refund
	 * 商户订单号和支付宝交易号不能同时为空。 trade_no、  out_trade_no如果同时存在优先取trade_no
	 * @param trade_no 商户订单号，和支付宝交易号二选一
	 * @param out_trade_no 支付宝交易号，和商户订单号二选一
	 * @param refund_amount 退款金额，不能大于订单总金额
	 * @param refund_reason 退款的原因说明
	 * @param out_request_no 标识一次退款请求，同一笔交易多次退款需要保证唯一，如需部分退款，则此参数必传。
	 * @throws AlipayApiException 
	 */
	public static String refund(String trade_no, String out_trade_no, String refund_amount, String refund_reason, String out_request_no) throws AlipayApiException{
		
		if(trade_no!=null||out_trade_no!=null){
    		
    		// SDK 公共请求类，包含公共请求参数，以及封装了签名与验签，开发者无需关注签名与验签     
    		AlipayClient client = new DefaultAlipayClient(AlipayConfig.URL, AlipayConfig.APPID, AlipayConfig.RSA_PRIVATE_KEY, AlipayConfig.FORMAT, AlipayConfig.CHARSET, AlipayConfig.ALIPAY_PUBLIC_KEY,AlipayConfig.SIGNTYPE);

    		AlipayTradeRefundRequest alipay_request = new AlipayTradeRefundRequest();

    		AlipayTradeRefundModel model=new AlipayTradeRefundModel();
    		model.setOutTradeNo(out_trade_no);
    		model.setTradeNo(trade_no);
    		model.setRefundAmount(refund_amount);
    		model.setRefundReason(refund_reason);
    		model.setOutRequestNo(out_request_no); //随机数  不是全额退款，部分退款必须使用该参数。同一个订单，不同的out_request_no代表部分退款
    		alipay_request.setBizModel(model);
    		
    		AlipayTradeRefundResponse alipay_response =client.execute(alipay_request);
    	    return alipay_response.getBody();
    	  }
		return "";
	}

	/***
	 * 用户提现：（商家向用户转账，页面中用户的虚余额会减少，用户的支付宝账号中余额增加）
	 * @param amount  转账金额，"xxx.xx"
	 * @param order_title 订单名，"余额提现"、"购买xxx"
	 * @param payee_account_or_id 有两种方式，可以选择邮箱账号或手机号的ALIPAY_LOGON_ID方式，"xxx@sandbox.com"
	 * @param payee_account_type 入参，recommand to select 2
	 * @param payee_realname 收款人实名认证(身份证上)的名字，沙箱则填“沙箱环境”
	 * @param remark 交易备注，任意
	 * @param payer_show_name 放款人昵称，本系统填“Edu教务管理系统”
	 * @return
	 */
	public static Map<String,String> fundTransfer(String amount, String order_title, String payee_account_or_id, int payee_account_type, String payee_realname, String remark, String payer_show_name){
		Map<String,String> resultMap=new HashMap<String,String>();
		// 设置请求参数
		JSONObject bizCont = new JSONObject();
		bizCont.put("out_biz_no", Dateutil.getTimeStampString());
		bizCont.put("trans_amount", amount);  // 转账金额如"1.68"
		bizCont.put("product_code", "TRANS_ACCOUNT_NO_PWD"); // fixed val
		bizCont.put("biz_scene", "DIRECT_TRANSFER");  // fixed val
		bizCont.put("order_title", order_title);
		JSONObject payee = new JSONObject(); // 收款人信息
		// method one: ALIPAY_USER_ID
		if (payee_account_type == 1) {
			payee.put("identity", payee_account_or_id);  // 填写收款方的user_id, 当前沙箱账号user_id详见AlipayConfig类
			payee.put("identity_type", "ALIPAY_USER_ID");
		}
		// method two: ALIPAY_LOGON_ID
		if (payee_account_type == 2) {
			payee.put("identity", payee_account_or_id);
			payee.put("identity_type", "ALIPAY_LOGON_ID");
			/*
			参与方真实姓名。如果非空，将校验收款支付宝账号姓名一致性。
			当 identity_type=ALIPAY_LOGON_ID 时，本字段必填。
			若传入该属性，则在支付宝回单中将会显示这个属性。
			 */
			payee.put("name", payee_realname); // 真人则填姓名，沙箱账号的姓名为"沙箱环境"
		}
		if (payee_account_type != 1 && payee_account_type != 2){
			resultMap.put("status", "false");
			resultMap.put("msg", "转账操作失败！收款人账号类型未填写");
			return resultMap;
		}
		bizCont.put("payee_info", payee);
		bizCont.put("remark", remark);
		JSONObject payer = new JSONObject(); // 放款人信息
		payer.put("payer_show_name", payer_show_name);
		bizCont.put("business_params", payer);
		// 准备发起请求
		AlipayFundTransUniTransferRequest alipayRequest = new AlipayFundTransUniTransferRequest();
		alipayRequest.setBizContent(bizCont.toJSONString());
		// Client Info
		AlipayClient client = new DefaultAlipayClient(AlipayConfig.URL, AlipayConfig.APPID, AlipayConfig.RSA_PRIVATE_KEY, AlipayConfig.FORMAT, AlipayConfig.CHARSET, AlipayConfig.ALIPAY_PUBLIC_KEY,AlipayConfig.SIGNTYPE);
		AlipayFundTransUniTransferResponse response = null;
		try {
			response = client.execute(alipayRequest);
			if("10000".equals(response.getCode())){
				resultMap.put("status", "true");
				resultMap.put("msg", "转账操作成功！");
			}else{
				resultMap.put("status", "false");
				resultMap.put("msg", response.getSubMsg());
			}
		} catch (AlipayApiException e) {
			e.printStackTrace();
			resultMap.put("status", "false");
			resultMap.put("msg", "转账操作失败！");
		}
		return resultMap;
	}

}
